package com.wang.tool.common;

import com.alibaba.fastjson.JSON;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 计时器
 * 记录每个动作的起止时间
 * 原因：StopWatch不支持并发记录模型
 *
 * @Author wangshaopeng
 * @Date 2022/3/5
 */
public class TimeWatch {

    /**
     * 开始时间
     */
    private long startTime = -1;

    /**
     * 耗时摘要
     * node-[start,end,Y/N]
     */
    private final Map<String, Triplet<Long, Long, Boolean>> costDetail = new LinkedHashMap<>();

    /**
     * 结束时间
     */
    private long stopTime = -1;

    {
        start();
    }


    /**
     * 开始
     */
    public void start() {
        startTime = System.currentTimeMillis();
    }

    /**
     * 结束
     */
    public TimeWatch stop() {
        stopTime = System.currentTimeMillis();
        return this;
    }

    /**
     * 计算全局耗时
     * 如果还未结束,拿当前时间计算
     *
     * @return
     */
    public long calGlobalCost() {
        return stopTime == -1 ? System.currentTimeMillis() - startTime : stopTime - startTime;
    }


    /**
     * 查看节点执行耗时
     *
     * @param code
     * @return
     */
    public Triplet<Long, Long, Boolean> findCost(String code) {
        if (code == null) {
            return null;
        }
        return costDetail.get(code);
    }

    /**
     * 记录节点开始
     * 线程安全
     *
     * @param code
     */
    public void markStart(String code) {
        if (code == null) {
            return;
        }
        synchronized (costDetail) {
            costDetail.put(code, new Triplet<>(System.currentTimeMillis() - startTime, null, null));
        }
    }

    /**
     * 记录节点结束
     *
     * @param code
     */
    public void markDone(String code, boolean success) {
        if (code == null) {
            return;
        }
        Triplet<Long, Long, Boolean> triplet = costDetail.get(code);
        if (triplet == null) {
            return;
        }
        triplet.setMiddle(System.currentTimeMillis() - startTime);
        triplet.setRight(success);
    }

    public long getStartTime() {
        return startTime;
    }

    public long getStopTime() {
        return stopTime;
    }

    public void setStartTime(long startTime) {
        this.startTime = startTime;
    }

    public void setStopTime(long stopTime) {
        this.stopTime = stopTime;
    }

    public Map<String, Triplet<Long, Long, Boolean>> getCostDetail() {
        return costDetail;
    }

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}
